
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;

@SuppressWarnings( {"unchecked","rawtypes"} )
public class CriteriaUtil{

	public static void setCategoryQuery( Object criteria , List<String> category, List<String> second ){
		List<Object> params = new ArrayList<>();
		String options = buildCateGoryQueryString( category , second ,params );
		if( StringUtils.isNotEmpty(  options ) ){
			andCriterion( criteria , options , params.toArray());
		}
	}
	public static String  buildCateGoryQueryString(  List<String> category, List<String> second ,List<Object> params ){
		List<String> options = new ArrayList<>();
		if( !CollectionUtils.isEmpty( category )){
			params.add( category );
			options.add( "rule_category in (?)" );
		}
		if( !CollectionUtils.isEmpty(second )){
			params.add( second );
			options.add( "rule_second_category in (?)" );
		}
		if( options.size()==0){
			return "";
		}
		return " ("+ StringUtils.join( options, " or " ) +") ";
	}

	/**
	 * 多对多查找，任意匹配
	 * @param criteria
	 * @param field 字段名
	 * @param codes 查找的代码列表
	 */
	public static  void  crossFindInSet( Object criteria , String field , List<String> codes ){
		SqlPr pr = SqlPr.crossFindInSet( field , codes );
		pr.applyTo(  criteria );
	}

	public static void andCriterion( Object criteria , String option, Object... args ){
		try{
			Method addCriterion = criteria.getClass().getSuperclass().getDeclaredMethod( "addCriterion" , String.class );
			addCriterion.setAccessible( true );
			AtomicInteger counter = new AtomicInteger( 0 );
			String option2 = TextUtil.replace( option ,"\\?" , matcher -> {
				int index = counter.getAndIncrement() ;
				if( args.length< index ){
					throw new IllegalArgumentException( "参数个数不对" );
				}
				Object value = args[index];
				if( value == null )
					return "null";
				if( value instanceof Collection ){
					return TextUtil.sqlQuoteList((Collection) value );
				}
				return TextUtil.sqlQuoteString( value );
			}) ;
			addCriterion.invoke( criteria ,"("+ option2 +")" );
		}catch( ReflectiveOperationException ex  ){
			throw new RuntimeException( ex );
		}
	}

	public static <A,R> List< R> queryInList( Object mapper , String and , List< A> nodes ){
		if( CollectionUtils.isEmpty( nodes )){
			return new ArrayList<>();
		}
		Object ret = invokeCriteriaMethod( mapper , and , nodes );
		return   (List<R>)ret;

	}

	public static  Object invokeCriteriaMethod( Object mapper , String methodName , Object... args ){
		try{
			Class< ? > mapperClass = mapper.getClass();
			Method[] methods = mapperClass.getMethods();
			Optional< Method > first1 = Arrays.stream( methods ).filter( p -> p.getName().equals( "selectByExample" ) ).findFirst();
			if( !first1.isPresent())
				throw new RuntimeException( "参数一不是mapper");
			Method selectByExample = first1.get();
			Class< ? >[] types = selectByExample.getParameterTypes();
			Class<?> exampleClass = types[0];
			Object example = exampleClass.newInstance();
			Object criteria = exampleClass.getMethod( "createCriteria" ).invoke( example );
			Method[] methods1 = criteria.getClass().getMethods();
			Optional< Method > first = Arrays.stream( methods1 ).filter( p -> p.getName().equals( methodName ) ).findFirst();
			if( !first.isPresent()){
				throw new RuntimeException( "参数二方法名不正确:" + methodName );
			}
			Method andInMethod = first.get();
			andInMethod.invoke( criteria , args );
			return selectByExample.invoke( mapper , example );
		}catch(ReflectiveOperationException e ){
			throw new RuntimeException( e );
		}
	}

	public static <T> void addArray( T[] arr , Function<List<T>,Object> method ){
		if( arr!=null && arr.length>0 ){
			method.apply( Arrays.asList( arr ) );
		}
	}
	public static <T> void addList( List<T> list , Function<List<T>,Object> method ){
		if( list!=null && list.size()>0 ){
			method.apply(list );
		}
	}
	public static void addIfExists( String value , Function<String,Object> method ){
		if( !StringUtils.isEmpty( value ) ){
			method.apply( value );
		}
	}


}
